package com.cdtye.shuoh.config.netty;

import javax.annotation.Resource;

import com.cdtye.shuoh.config.gb28181.transmit.cmd.impl.SIPCommander;
import com.cdtye.shuoh.domain.Frame.*;
import com.cdtye.shuoh.domain.device.entity.Device;
import com.cdtye.shuoh.domain.device.entity.DeviceLocation;
import com.cdtye.shuoh.domain.enums.*;
import com.cdtye.shuoh.domain.product.entity.Product;
import com.cdtye.shuoh.service.device.DeviceService;
import com.cdtye.shuoh.service.device.impl.DeviceDatasServiceImpl;
import com.cdtye.shuoh.service.product.ProductService;
import com.cdtye.shuoh.util.text.Crc16Utils;
import com.cdtye.shuoh.util.text.DataConverter;
import com.cdtye.shuoh.util.text.DateUtils;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;

@Component
@Sharable
@ConditionalOnProperty(value = "netty.enabled", havingValue = "true")
public class ServerHandler extends ChannelInboundHandlerAdapter {

    private final Logger logger = LoggerFactory.getLogger(ServerHandler.class);

    @Resource
    private DeviceDatasServiceImpl deviceDatasService;

    @Resource
    private DeviceService deviceService;

    @Resource
    private ProductService productService;


    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);



    @Override
    public void userEventTriggered(ChannelHandlerContext channelHandlerContext, Object evt) throws Exception {
        InetSocketAddress insocket = (InetSocketAddress) channelHandlerContext.channel().remoteAddress();
        String ip = insocket.getAddress().getHostAddress();
        int port = insocket.getPort();
        String connector = ip + ":" + port;
        logger.info("======"+channelHandlerContext.channel().remoteAddress()+"超时"+"===========");
        IdleStateEvent stateEvent = (IdleStateEvent) evt;
        if (IdleState.READER_IDLE.equals(stateEvent.state())) {
         deviceService.updateDeviceConnectStatusByConnector(connector,DeviceConnectStatus.OFFLINE.getValue());
        }
//        if (3 < readerIdleCount) {
//            // 通知客户端关闭连接
//            channelHandlerContext.channel().writeAndFlush("close");
//            channelHandlerContext.channel().close();
//            System.out.println("释放客户端连接");
//        }
    }

    /**
     * 获取数据
     * @param ctx 上下文
     * @param msg 获取的数据
     * @throws UnsupportedEncodingException
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ServerHandler.channelGroup.forEach(ch->{
            logger.info("客户端地址"+ch.remoteAddress());
        });
        String receiveMessage = (String) msg;
        String rmsg = handlerMessage(receiveMessage,ctx);
        logger.info(rmsg);
        if(null == rmsg){
            return;
        }
        ctx.writeAndFlush(rmsg.toUpperCase());
    }

    /**
     * 有客户端与服务器发生连接时执行此方法
     * 1.打印提示信息
     * 2.将客户端保存到 channelGroup 中
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        logger.warn("有新的客户端与服务器发生连接。客户端地址：" + channel.remoteAddress());
        channelGroup.add(channel);
    }

    /**
     * 当有客户端与服务器断开连接时执行此方法，此时会自动将此客户端从 channelGroup 中移除
     * 1.打印提示信息
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
    }




    private String handlerMessage(String message,ChannelHandlerContext ctx) throws Exception {
        message = message.replaceAll("\\s*", "").toUpperCase();
        String sync = message.substring(0,2*2);
        String packetLength = message.substring(2*2,2*4);
        String cmdId = message.substring(4*2,21*2);
        String frameType = message.substring(21*2,22*2);
        String packetType = message.substring(22*2,23*2);
        String frameNo = message.substring(23*2,24*2);
        String deviceIdentification = DataConverter.hexString2String(cmdId);
        String crc16 = message.substring(message.length()-6,message.length()-2);
        String end = message.substring(message.length()-2);
        logger.info("Frame_type"+frameType);
        logger.info("Packet_type"+packetType);
        //heartBeat Frame
        if(FrameType.WORK_STATE.getCode().equals(frameType) && PacketType.HEART_BEAT.getCode().equals(packetType)){
            logger.info("heart packet");
            HeartBeatFrame heartBeatFrame = new HeartBeatFrame();
            //todo 心跳处理 设备新增上线
            InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
            String ip = insocket.getAddress().getHostAddress();
            int port = insocket.getPort();
            String connector = ip + ":" + port;
            Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
            if(null != device){
                device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                device.setConnector(connector);
                deviceService.updateDeviceByDeviceIdentification(device);
            }
            return Crc16Utils.replaceCrcStr(sync.concat("0600").concat(cmdId).concat(FrameType.WORK_STATE_RESPONSE.getCode()).concat(packetType)
                    .concat(frameNo).concat("FF").concat("00").concat(DataConverter.reverseHex(Long.toHexString(DateUtils.getMillis2()/1000))).concat("000096"));
        } else if(FrameType.VIDEO_REQUEST.getCode().equals(frameType) || FrameType.VIDEO_REQUEST_1.getCode().equals(frameType)){
            if(PacketType.PHOTO.getCode().equals(packetType)){
                logger.info("请求上送照片 packet");
                InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
                String ip = insocket.getAddress().getHostAddress();
                int port = insocket.getPort();
                String connector = ip + ":" + port;
                Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
                if(null == device){
                    device = new Device();
                    Product product = productService.findOneByModel("image");
                    if(null!=product){
                        device.setProductIdentification(product.getProductIdentification());
                    }else {
                        return null;
                    }
                    device.setDeviceType(DeviceType.COMMON.getValue());
                    device.setDeviceIdentification(deviceIdentification);
                    device.setProtocolType("HTTP");
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setDeviceName(deviceIdentification);
                    device.setConnector(connector);
                    device.setDeviceLocation(new DeviceLocation());
                }else{
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setConnector(connector);
                }
                deviceService.updateDeviceByDeviceIdentification(device);


                //设备端发送请求上传图像数据报，平台端收到后原命令返回给设备端
//                String channelNo = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(24*2,25*2))));
//                String channelNoHex = message.substring(24*2,25*2);
//                String presettingNo = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(25*2,26*2))));
//                String presttingNoHex = message.substring(25*2,26*2);
//                String packetHigh = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(26*2,27*2))));
//                String packetLow = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(27*2,28*2))));
//                ImageRequestFrame imageRequestFrame = new ImageRequestFrame(channelNo,presettingNo,packetHigh,packetLow,sync,packetLength,cmdId,frameType,packetType,frameNo,crc16,end,deviceIdentification,channelNoHex,presttingNoHex);
                return message;
            }else if(PacketType.IMAGE_DATA.getCode().equals(packetType)){
                logger.info("远程图像数据报 packet");
                InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
                String ip = insocket.getAddress().getHostAddress();
                int port = insocket.getPort();
                String connector = ip + ":" + port;
                Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
                if(null == device){
                    device = new Device();
                    Product product = productService.findOneByModel("image");
                    if(null!=product){
                        device.setProductIdentification(product.getProductIdentification());
                    }else {
                        return null;
                    }
                    device.setDeviceType(DeviceType.COMMON.getValue());
                    device.setDeviceIdentification(deviceIdentification);
                    device.setProtocolType("HTTP");
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setDeviceName(deviceIdentification);
                    device.setConnector(connector);
                    device.setDeviceLocation(new DeviceLocation());
                }else{
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setConnector(connector);
                }
                deviceService.updateDeviceByDeviceIdentification(device);

                //设备端接收验证无误后即开始上传图像数据报文
                String channelNo = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(24*2,25*2))));
                String channelNoHex = message.substring(24*2,25*2);
                String packetNo = String.valueOf(DataConverter.parseHexStr2Integer(message.substring(26*2,28*2)));
                String subpacketNo = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(28*2,30*2))));
                String presettingNo = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(25*2,26*2))));
                String presttingNoHex = message.substring(25*2,26*2);
                String sample = message.substring(30*2,message.length()-6);
                ImageDataFrame imageDataFrame = new ImageDataFrame(channelNo,presettingNo,packetNo,subpacketNo,sample,sync,packetLength,cmdId,frameType,packetType,frameNo,crc16,end,deviceIdentification,channelNoHex,presttingNoHex);
                //todo 处理图像数据
                deviceDatasService.processingImageData(imageDataFrame);
            }else if(PacketType.IMAGE_DATA_END.getCode().equals(packetType)){
                logger.info("远程图像数据上送结束标记 packet");
                InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
                String ip = insocket.getAddress().getHostAddress();
                int port = insocket.getPort();
                String connector = ip + ":" + port;
                Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
                if(null == device){
                    device = new Device();
                    Product product = productService.findOneByModel("image");
                    if(null!=product){
                        device.setProductIdentification(product.getProductIdentification());
                    }else {
                        return null;
                    }
                    device.setDeviceType(DeviceType.COMMON.getValue());
                    device.setDeviceIdentification(deviceIdentification);
                    device.setProtocolType("HTTP");
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setDeviceName(deviceIdentification);
                    device.setConnector(connector);
                    device.setDeviceLocation(new DeviceLocation());
                }else{
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setConnector(connector);
                }
                deviceService.updateDeviceByDeviceIdentification(device);

                String channelNo = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(24*2,25*2))));
                String channelNoHex = message.substring(24*2,25*2);
                String presettingNo = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(25*2,26*2))));
                String presttingNoHex = message.substring(25*2,26*2);
                String timeStamp = String.valueOf(DataConverter.hex2Long(DataConverter.reverseHex(message.substring(26*2,30*2))));
                ImageRequestEndFrame imageRequestEndFrame = new ImageRequestEndFrame(channelNo,presettingNo,timeStamp,sync,packetLength,cmdId,frameType,packetType,frameNo,crc16,end,deviceIdentification,channelNoHex,presttingNoHex);
                //todo 处理图像结束帧响应
                return deviceDatasService.processingImageSendEnd(imageRequestEndFrame);
            }
        }
            if(FrameType.DATA_REQUEST.getCode().equals(frameType) && PacketType.ATMOSPHERE.getCode().equals(packetType)){
                logger.info("气象环境类数据报 packet");
                //todo 心跳处理 设备新增上线
                InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
                String ip = insocket.getAddress().getHostAddress();
                int port = insocket.getPort();
                String connector = ip + ":" + port;
                Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
                if(null == device){
                    device = new Device();
                    Product product = productService.findOneByModel("atmosphere");
                    if(null!=product){
                        device.setProductIdentification(product.getProductIdentification());
                    }else {
                        return null;
                    }
                    device.setDeviceType(DeviceType.COMMON.getValue());
                    device.setDeviceIdentification(deviceIdentification);
                    device.setProtocolType("HTTP");
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setDeviceName(deviceIdentification);
                    device.setConnector(connector);
                    device.setDeviceLocation(new DeviceLocation());
                }else{
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setConnector(connector);
                }
                deviceService.updateDeviceByDeviceIdentification(device);
                String componentId = message.substring(24*2,41*2);
                String timeStamp = String.valueOf(DataConverter.hex2Long(DataConverter.reverseHex(message.substring(41*2,45*2))));
                String average_windspeed_10min = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(45*2,49*2))));
                String average_winddirection_10min = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(49*2,51*2))));
                String max_windspeed = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(51*2,55*2))));
                String extreme_windspeed = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(55*2,59*2))));
                String standard_windspeed = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(59*2,63*2))));
                String air_temperature = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(63*2,67*2))));
                String humidity = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(67*2,69*2))));
                String air_pressure = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(69*2,73*2))));
                String precipitation = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(73*2,77*2))));
                String precipitation_intensity = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(77*2,81*2))));
                String radiation_intensity = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(81*2,83*2))));
                AtmosphereFrame atmosphereFrame = new AtmosphereFrame(componentId,timeStamp,average_windspeed_10min,average_winddirection_10min,max_windspeed,extreme_windspeed,standard_windspeed,air_temperature,humidity,air_pressure,precipitation,precipitation_intensity,radiation_intensity,sync,packetLength,cmdId,frameType,packetType,frameNo,crc16,end,deviceIdentification);
                //todo 处理气象数据
                return deviceDatasService.processingAtmosphereFrame(atmosphereFrame);
            }else if(FrameType.DATA_REQUEST.getCode().equals(frameType) && PacketType.ICE_COVER.getCode().equals(packetType)){
                logger.info("结冰 packet");
                //todo 心跳处理 设备新增上线
                InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
                String ip = insocket.getAddress().getHostAddress();
                int port = insocket.getPort();
                String connector = ip + ":" + port;
                Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
                if(null == device){
                    device = new Device();
                    Product product = productService.findOneByModel("iceCover");
                    if(null!=product){
                        device.setProductIdentification(product.getProductIdentification());
                    }else {
                        return null;
                    }
                    device.setDeviceType(DeviceType.COMMON.getValue());
                    device.setDeviceIdentification(deviceIdentification);
                    device.setProtocolType("HTTP");
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setDeviceName(deviceIdentification);
                    device.setConnector(connector);
                    device.setDeviceLocation(new DeviceLocation());
                }else{
                    device.setConnectStatus(DeviceConnectStatus.ONLINE.getValue());
                    device.setConnector(connector);
                }
                deviceService.updateDeviceByDeviceIdentification(device);
                String componentId = message.substring(24*2,41*2);
                String timeStamp = String.valueOf(DataConverter.hex2Long(DataConverter.reverseHex(message.substring(41*2,45*2))));
                String temperature = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(45*2,49*2))));
                String icing_thickness = String.valueOf(DataConverter.parseHex2Float(DataConverter.reverseHex(message.substring(49*2,53*2))));
                String icing_state = String.valueOf(DataConverter.parseHexStr2Integer(DataConverter.reverseHex(message.substring(53*2,54*2))));
                IceCoverFrame iceCoverFrame = new IceCoverFrame(componentId,timeStamp,temperature,icing_thickness,icing_state,sync,packetLength,cmdId,frameType,packetType,frameNo,crc16,end,deviceIdentification);
                //todo 覆冰数据
                return deviceDatasService.processingIceCoverFrame(iceCoverFrame);
            }

        return null;
    }


    /**
     *  通道读取事件
     * @param
     * @param
     * @throws Exception
     */
//    @Override
//    public void channelRead(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
//        ByteBuf buf = (ByteBuf) msg;
//        byte[] bytes = new byte[buf.readableBytes()];
//        // 复制内容到字节数组bytes
//        buf.readBytes(bytes);
//
//        // 将接收到的数据转为字符串，此字符串就是客户端发送的字符串
//        String receiveStr = DataConverter.receiveHexToString(bytes);
//        System.out.println("接收到的数据"+receiveStr);
//        String rmsg = deviceDatasService.processingHttpDatas(receiveStr);
//        System.out.println("返回数据"+rmsg);
//        if(null == rmsg){
//            return;
//        }
//        try {
//            // netty需要用ByteBuf传输
//            ByteBuf buff = Unpooled.buffer();
//            // 对接需要16进制
//            buff.writeBytes(DataConverter.hexString2Bytes(rmsg));
//            channelHandlerContext.writeAndFlush(buff);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}


